package models

//import "time"
import "gorm.io/gorm"
//import "go_part/utils"
import "fmt"
import set "gopkg.in/fatih/set.v0"
import (
	"net/http"
	// "github.com/gin-gonic/gin"
	// "github.com/asaskevich/govalidator"
	"github.com/gorilla/websocket"
	"strconv"
	"sync"
	"net"
	"encoding/json"
)

type Message struct{
	gorm.Model
	FormId int64
	TargetId int64
	Type int // 群聊  私聊 广播
	Media int // 文字 图片 音频 视频
	Content string // 内容
	Pic string //
	Url string //
	Desc string //
	Amount int

 }


func (table *Message) TableName() string {

	return "message"
}

type Node struct {
	Conn *websocket.Conn
	DataQueue chan []byte
	GroupSets set.Interface
}

//映射关系
var clientMap map[int64] *Node = make(map[int64] *Node, 0)

//读写锁
var rwLocker sync.RWMutex

func Chat(writer http.ResponseWriter, request *http.Request){
	//校验token
	query := request.URL.Query()
	Id := query.Get("userId")
	userId,_ := strconv.ParseInt(Id,10,64)
	// msgType := query.Get("Type")
	// targetId := query.Get("targetId")
	// context := query.Get("context")
	isvalida := true // checkToken()  
	conn,err := (&websocket.Upgrader{
		CheckOrigin :func(r *http.Request) bool {
				return isvalida
		},
	}).Upgrade(writer, request, nil)
	if err != nil {
		fmt.Println(err)
		return
	} 
	//2、
	node := &Node{
		Conn :conn,
		DataQueue: make(chan []byte, 50),
		GroupSets: set.New(set.ThreadSafe),
	}

	//3、

	//4、
	rwLocker.Lock()
	clientMap[userId] = node
	rwLocker.Unlock()

	//5、 完成发送逻辑
	go sendProc(node)
	//6、完成接受逻辑
	go recvProc(node)
	sendMsg(userId, []byte("欢迎进入聊天系统"))

}

func sendProc(node *Node){
	for{
		select {
			case data := <- node.DataQueue:
				fmt.Println("[ws]sendProc >>>> msg :",string(data))
				err := node.Conn.WriteMessage(websocket.TextMessage,data)
				if err != nil {
					fmt.Println(err)
					return 
				}
		}
	}
}

func recvProc(node *Node) {

	for{
		_,data,err := node.Conn.ReadMessage()
		if err != nil {
			fmt.Println(err)
					return 
		}
		broadMsg(data)
		fmt.Println("[ws] <<<<< ",data)
	}

}

var udpsendChan chan []byte = make(chan []byte, 1024)

func broadMsg(data []byte){
	udpsendChan <- data
}

func init () {
	go udpSendProc()
	go udpRecvProc()
	fmt.Println("init goroutine ")
}

func udpSendProc(){
	con, err := net.DialUDP("udp",nil,&net.UDPAddr{
		IP: net.IPv4(192, 168, 1 ,255),
		Port: 3000,
	})
	defer con.Close()
	if err != nil {
		fmt.Println(err)	
	}
	for{
		select {
			case data := <- udpsendChan:
				_,err := con.Write(data)
				if err != nil {
					fmt.Println(err)
					return 
				}
		}
	}
}

func udpRecvProc(){
	con,err := net.ListenUDP("udp",&net.UDPAddr{
		IP : net.IPv4zero,
		Port: 3000,
	})
	if err != nil {
		fmt.Println(err)
	}
	defer con.Close()
	for{
		var buf [512] byte
		n, err := con.Read(buf[0:])
		if err != nil {
			fmt.Println(err)
			return
		}
		dispatch(buf[0:n])
	}
}

func dispatch(data []byte){
	msg := Message{}
	err := json.Unmarshal(data, &msg)
	if err != nil {
		fmt.Println(err)
		return
	}
	switch msg.Type {
		case 1 : 
			fmt.Println("dispatch buf :", string(data))
			sendMsg(msg.FormId, data) //私信
		// case 2 : sendGroupMsg()
		// case 3 : sendAllMsg()
		//case 4 : 
	}
}

func sendMsg(userId int64,  msg []byte) {
	rwLocker.Lock()
	node , ok := clientMap[userId]
	rwLocker.Unlock()
	if ok {
		node.DataQueue <- msg
	}
}